#include "HttpConnection.h"
#include <iostream>
#include <string>
#include "LogicSystem.h"

unsigned char ToHex(unsigned char x)
{
    return  x > 9 ? x + 55 : x + 48;
}

unsigned char FromHex(unsigned char x)
{
    unsigned char y;
    if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
    else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
    else if (x >= '0' && x <= '9') y = x - '0';
    else assert(0);
    return y;
}


std::string UrlEncode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        //判断是否仅有数字和字母构成
        if (isalnum((unsigned char)str[i]) ||
            (str[i] == '-') ||
            (str[i] == '_') ||
            (str[i] == '.') ||
            (str[i] == '~'))
            strTemp += str[i];
        else if (str[i] == ' ') //为空字符
            strTemp += "+";
        else
        {
            //其他字符需要提前加%并且高四位和低四位分别转为16进制
            strTemp += '%';
            strTemp += ToHex((unsigned char)str[i] >> 4);
            strTemp += ToHex((unsigned char)str[i] & 0x0F);
        }
    }
    return strTemp;
}


std::string UrlDecode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        //还原+为空
        if (str[i] == '+') strTemp += ' ';
        //遇到%将后面的两个字符从16进制转为char再拼接
        else if (str[i] == '%')
        {
            assert(i + 2 < length);
            unsigned char high = FromHex((unsigned char)str[++i]);
            unsigned char low = FromHex((unsigned char)str[++i]);
            strTemp += high * 16 + low;
        }
        else strTemp += str[i];
    }
    return strTemp;
}




HttpConnection::HttpConnection(boost::asio::io_context& ioc)
:socket_(ioc),
deadline_(socket_.get_executor(),std::chrono::seconds(60))
{

}

void HttpConnection::Start()
{

    auto self(shared_from_this());
    self->CheckDeadLine();
    http::async_read(socket_,buffer_,request_,[self](::boost::beast::error_code ec, ::std::size_t bytes_transferred){
        if(ec)
        {
            std::cerr<<"http read error:"<<ec.message()<<std::endl;
            return;
        }
        try
        {
            //开始处理读取的数据
            self->HandleReq();
            

        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
        
    });

}


void HttpConnection::CheckDeadLine()
{
    auto self(shared_from_this());
    //开始异步等待
    deadline_.async_wait([self](const boost::system::error_code& ec){
        //在没有出错的情况下
        if(!ec)
        {
            //若超时则断开连接
            self->socket_.close();
        }
    });
}

void HttpConnection::HandleReq()
{
    //开始处理HTTP的request请求
    response_.version(request_.version());
    //短连接
    response_.keep_alive(false);
    //查看request请求的方法
    switch (request_.method())
    {
        /**
         * @brief 大前提说明：result和content-type都是在对应的回调函数方法中自己设定的
         *          除非返回的是false，此时才需要在下面的代码中声明result和content-type
         */
    case http::verb::get:
    {
        //先解析GET参数
        PreParseGetParam();

                //进行业务处理
        bool success = LogicSystem::GetInstance()->HandleGet(get_url_,shared_from_this());
        if(!success)
        {
            response_.result(http::status::not_found);
            response_.set(http::field::content_type,"text/plain; charset=utf-8");

            beast::ostream(response_.body())<<"GET: url not found:"<<request_.target();
        }
        response_.result(http::status::ok);
        
        break;
    }

    case http::verb::post:
        //进行业务处理
        {
            bool success = LogicSystem::GetInstance()->HandlePost(request_.target(),shared_from_this());
            if(!success)
            {
                response_.result(http::status::not_found);
                response_.set(http::field::content_type,"text/plain; charset=utf-8");
                beast::ostream(response_.body())<<"POST: url not found:"<<request_.target();
            }
        }
        break;
    default:
        //若为其他方法则404
        response_.result(http::status::not_found);
        response_.set(http::field::content_type, "text/plain; charset=utf-8");
        std::string errMsg("404 method Not Found");
        response_.set(http::field::content_length, std::to_string(errMsg.size()));
        boost::beast::ostream(response_.body())<<errMsg;
        //设置响应体的长度
        break;
    }
    response_.set(http::field::server, "HSL Boost beast Server");
    //设置响应体长度
    response_.set(http::field::content_length, std::to_string(response_.body().size()));

    WriteResponse();
}
void HttpConnection::WriteResponse()
{
    auto self(shared_from_this());
    //异步的将结果返回给客户端
    http::async_write(socket_,response_,[self](const boost::beast::error_code& ec, ::std::size_t bytes_transferred){
        //忽略bytes_transferred
        boost::ignore_unused(bytes_transferred);
        if (ec)
        {
            std::cerr<<"http write error:"<<ec.message()<<std::endl;
            return;
        }
        //若成功则关闭发送缓存，同时取消异步定时
        self->socket_.shutdown(tcp::socket::shutdown_send);
        self->deadline_.cancel();
        
    });
}


void HttpConnection::PreParseGetParam() {
    // 提取 URI  
    auto uri = request_.target();
    // 查找查询字符串的开始位置（即 '?' 的位置）  
    auto query_pos = uri.find('?');
    if (query_pos == std::string::npos) {
        get_url_ = uri;
        return;
    }

    get_url_ = uri.substr(0, query_pos);
    std::string query_string = uri.substr(query_pos + 1);
    std::string key;
    std::string value;
    size_t pos = 0;
    while ((pos = query_string.find('&')) != std::string::npos) {
        auto pair = query_string.substr(0, pos);
        size_t eq_pos = pair.find('=');
        if (eq_pos != std::string::npos) {
            key = UrlDecode(pair.substr(0, eq_pos)); // 假设有 url_decode 函数来处理URL解码  
            value = UrlDecode(pair.substr(eq_pos + 1));
            get_params_[key] = value;
        }
        query_string.erase(0, pos + 1);
    }
    // 处理最后一个参数对（如果没有 & 分隔符）  
    if (!query_string.empty()) {
        size_t eq_pos = query_string.find('=');
        if (eq_pos != std::string::npos) {
            key = UrlDecode(query_string.substr(0, eq_pos));
            value = UrlDecode(query_string.substr(eq_pos + 1));
            get_params_[key] = value;
        }
    }
}